#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#ifndef NDEBUG
	#define DOUT( toprint ) printf( "\n# " toprint )        //!< Debug output, prints a plain text line preceded by #
	#define DPUT( toput , x ) printf( "\n# " toput , x )	//!< Debug put, a DOUT with a single variable inside
	#define DLN                                             //!< Debug line, doesn't exist in release ( with NDEBUG defined )
	#define DPUTCLOSURE	DOUT("=============================================================================");\
		DPUT("FILE: %s", __FILE__ );\
		DPUT("COMPILATION DATE: %s", __DATE__ );\
		DPUT("COMPILATION TIME: %s\n", __TIME__ )//!< Put a closing statement, complete with datestamp and finename.
#else
	#define DOUT
	#define DPUT
	#define DLN if(0)
	#define DPUTCLOSURE
#endif

const int STK_SZ = 10;
const int ST_WRONG = -1;
const int POISON = -6666;

typedef double stk_d;
typedef struct stk {
	long num;
	stk_d* data;
} stk;

void stk_construct( stk* tobuild )
{
	( tobuild -> data ) = ( stk_d* ) calloc( STK_SZ, sizeof( double ) );
	tobuild -> num = 0;
}
void stk_destruct( stk* in )
{
	( in -> num ) = POISON;
	free( in -> data );
}

int stk_OK( const stk* const chk_in )
{
	return(
	( 0 > ( chk_in -> num )  || ( chk_in -> num ) > STK_SZ ) 
		? 0 
		: 1
		)
}
void stk_Dump( const stk* const gabg_in )
{
	//freopen("dump.txt", "w+", stdout);
	printf( "\nSTACK\n" );

	if( gabg_in == NULL ) {
		printf( "!! Everything is wrong - Stack_Dump received a NULL stack !!" );
		DPUTCLOSURE;
		return;
	}

	printf( stk_OK( gabg_in ) ? "ok\n" : "WARNING@GARBAGE_AHEAD\n" );

	for( int i = 0; i < STK_SZ; i++ ) {
		printf( "%lg\t", ( gabg_in -> data )[i] );
		printf( ( ( gabg_in -> num ) < i ) ? "*\n" : "\n" );
	}

	DPUTCLOSURE;
};

bool stk_full( const stk* const full_in )
{
	assert(( "Stk_full received an OK stack", stk_OK(full_in) ));
	return( ( full_in -> num ) == STK_SZ );
}
bool stk_mt( const stk* const mt_in )
{
	assert(( "Stk_MT received an OK stack", stk_OK(mt_in) ));
	return( ( mt_in -> num ) ? 0 : 1 );
}

int stk_push( stk* const push_in, stk_d topush )
{
	assert(( "Stack_push received a valid stack", push_in != NULL ));
	assert(( "Stack_push got an OK stack", stk_OK(push_in) ));

	bool full = stk_full( push_in );

	DLN if( full ) DOUT( "Stack_push has received a FULL stack!" );

	if( stk_OK( push_in ) && !full ) {
		( push_in -> data )[ push_in -> num ] = topush;
		( push_in -> num )++;
		return 1;
	} else
		return( full ? 0 : ST_WRONG );
}
int stk_pop( stk* const pop_in, stk_d* out )
{
	assert(( "Stack_pop received a valid stack", pop_in != NULL ));
	assert(( "Stack_pop received a valid output container", out != NULL ));
	assert(( "Stack_pop received an OK stack", stk_OK(pop_in) ));

	bool mt = stk_mt( pop_in );

	DLN if( mt ) DOUT( "Stack_pop has received an EMPTY stack!" );

	if( stk_OK( pop_in ) && !mt ) {
		*out = ( pop_in -> data )[( pop_in -> num ) - 1 ];
		--( pop_in -> num );
		return 1;
	} else {
		return( mt ? 0 : ST_WRONG );
	}
}

#define MAKE_A_FUNC_( name, oper, stack) \
	void stk_##name(stk* stack){\
		stk_d a = 0, b = 0;	\
		\
		stk_pop(stack, &a);	\
		stk_pop(stack, &b);	\
		\
		a oper##= b;		\
		stk_push(stack, a);	\
	}

MAKE_A_FUNC_( SUM, + , sopp );
MAKE_A_FUNC_( SUB, - , sopm );
MAKE_A_FUNC_( MUL, * , sopc );
MAKE_A_FUNC_( DIV, / , sops );

#undef MAKE_A_FUNC_

void stk_EXP( stk* sope )
{
	stk_d a = 0;
	stk_pop( sope, &a );

	a = exp( a );

	stk_push( sope, a );
}

void stk_POW( stk* soppow )
{
	stk_d a = 1, b = 1;
	stk_pop( soppow, &a );
	stk_pop( soppow, &b );

	a = pow( a, ( int )b );

	stk_push( soppow, a );
}
